import type { TreeData } from 'element-plus/es/components/tree-v2/src/types'
import { reactive, toRefs } from 'vue'
const defaultProps = {
  props: {
    value: '_id',
    label: 'label',
    children: 'children'
  }
}

export interface UseTreeProps {
  treeData: any
  treeRef: any
  setTree: (data: any) => void
  props?: Record<string, string>
}

export interface UseTreeState {
  query: string | undefined
}

export const treeForeach = (tree: any, func: any) => {
  let node: any
  const list = [
    ...tree.map((i: any) => ({
      ...i,
      index: tree.findIndex((m: any) => m._id === i._id),
      list: tree,
      isLast:
        tree.findIndex((m: any) => m._id === i._id) === tree.length - 2 ||
        tree.findIndex((m: any) => m._id === i._id) === tree.length - 1
    }))
  ]
  let res = false
  while ((node = list.shift()) && !res) {
    res = func(node, list.length, list)
    if (node.children) {
      list.push(
        ...node.children.map((i: any) => ({
          ...i,
          index: node.children.findIndex((m: any) => m._id === i._id),
          list: node.children,
          isLast:
            node.children.findIndex((m: any) => m._id === i._id) === node.children.length - 2 ||
            node.children.findIndex((m: any) => m._id === i._id) === node.children.length - 1
        }))
      )
    }
  }
}
export default (params: UseTreeProps) => {
  const props = {
    ...defaultProps,
    ...params
  }

  /**
   * 过滤时的input函数
   * @param query
   */
  const onChange = (query: string) => {
    props.treeRef.value?.filter(query)
  }
  /**
   * 过滤时的filter-method
   * @param query
   * @param node
   * @returns
   */
  const filterMethod: any = (query: string, node: any) => {
    return node[props.props.label]?.includes(query)
  }
  /**
   * 当数据量非常庞大的时候，使用 reactive 数据将导致性能非常低下，所以我们提供了一个能够规避这种情况的方法
   * @param data
   * @returns
   */
  const setData = (data: TreeData) => props.treeRef.value?.setData(data)

  /**
   * 每次更新完treeData后重新调用更新视图
   * @returns
   */
  const setTreeData = () => props.setTree(props.treeData.value)

  /**
   * 添加兄弟节点
   * @param indexNode 参照的节点
   * @param sibling 同级的节点
   * @param list 当前层级遍历列表，默认为props.treeData
   * @returns
   */
  const addSibling = (indexNode: any, sibling: any, list: any[] = props.treeData) => {
    treeForeach(list, (node: any) => {
      if (node[props.props.value] === indexNode.value.key) {
        node.list.unshift(sibling)
        setTreeData()
        return true
      }
      return false
    })
  }

  /**
   * 添加子节点
   * @param indexNode 要添加子节点的元素
   * @param child 添加的子节点
   */
  const addChild = (indexNode: any, child: any) => {
    if (!indexNode.children) {
      indexNode.children = []
    }
    indexNode.children.unshift(child)
    setTreeData()
  }

  /**
   * 编辑节点
   * @param node 当前节点
   * @param key
   * @param value
   */
  const editNode = (node: any, key: string, value: any) => {
    node[key] = value
    setTreeData()
  }

  /**
   * 数组位置交互
   * @param list
   * @param i
   * @param m
   */
  const exchangePos = (list: any[], i: number, m: number) => {
    const temp = list[i]
    list[i] = list[m]
    list[m] = temp
  }

  /**
   * 节点上移
   * @param indexNode 当前要移动的节点
   * @param list 需要遍历的数组，默认为props.treeData
   * @returns
   */
  const moveUp = (indexNode: any, list: any[] = props.treeData.value) => {
    let target = null
    const key = props.props.value
    treeForeach(list, (node: any) => {
      if (node[key] === indexNode[key]) {
        target = node.list[node.index - 1]
        exchangePos(node.list, node.index - 1, node.index)
        setTreeData()
        return true
      }
      return false
    })
    return target
  }

  /**
   * 节点下移
   * @param indexNode 当前要移动的节点
   * @param list 需要遍历的数组，默认为props.treeData
   * @returns
   */
  const moveDown = (indexNode: any, list: any[] = props.treeData.value) => {
    let target = null
    const key = props.props.value
    treeForeach(list, (node: any) => {
      if (node[key] === indexNode[key]) {
        target = node.list[node.index + 1]
        exchangePos(node.list, node.index + 1, node.index)
        setTreeData()
        return true
      }
      return false
    })
    return target
  }

  /**
   * 获取节点在列表中的index
   * @param indexNode
   * @param list
   * @returns {index, isLast} index为节点在列表中的索引，当前节点是否为列表中最后一个元素
   */
  const getNodeIndex: any = (indexNode: any, list: any = props.treeData.value) => {
    let res = {}
    treeForeach(list, (node: any, _: any, arr: any) => {
      if (node[props.props.value] === indexNode._id) {
        res = {
          node,
          list: arr
        }
        return true
      }
      return false
    })
    return res
  }
  const state: UseTreeState = reactive({
    query: undefined
  })
  const { query } = toRefs(state)
  return {
    filter: { onChange, filterMethod, query },
    setData,
    setTreeData,
    addSibling,
    addChild,
    editNode,
    moveUp,
    moveDown,
    getNodeIndex,
    ...toRefs(state)
  }
}
